Skip to content

feat(config): add service resource detector support for declarative config#5003

Open
MikeGoldsmith wants to merge 18 commits intoopen-telemetry:mainfrom
MikeGoldsmith:mike/config-resource-detector-service
Open

feat(config): add service resource detector support for declarative config#5003
MikeGoldsmith wants to merge 18 commits intoopen-telemetry:mainfrom
MikeGoldsmith:mike/config-resource-detector-service

Conversation

@MikeGoldsmith
Copy link
Copy Markdown
Member

@MikeGoldsmith MikeGoldsmith commented Mar 20, 2026

Description

Implements service resource detector support in create_resource() for the declarative configuration pipeline, as part of the ongoing work tracked in the following PRs:

What's included

  • Wires detection_development.detectors[].service via _run_detectors():
    • Sets service.instance.id to a random UUID on every process start
    • Reads OTEL_SERVICE_NAME env var for service.name if set (mirrors other SDK behaviour)
  • Explicit config attributes always take priority over detector-provided values
  • service.name=unknown_service default is set at the lowest priority so any detector or explicit attribute can override it
  • 9 new tests covering instance ID uniqueness, env var reading, explicit attribute override, opt-in behaviour, and attribute filtering

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

  • 9 unit tests in tests/_configuration/test_resource.py
  • Includes explicit tests that the detector does not run when detection_development or detectors is absent

Does This PR Require a Contrib Repo Change?

  • Yes.
  • No.

Checklist:

  • Followed the style guidelines of this project
  • Changelogs have been updated
  • Unit tests have been added
  • Documentation has been updated

Assisted-by: Claude Sonnet 4.6

Implements create_resource() and create_propagator()/configure_propagator()
for the declarative file configuration. Resource creation does not read
OTEL_RESOURCE_ATTRIBUTES or run any detectors (matches Java/JS SDK behavior).
Propagator configuration always calls set_global_textmap to override Python's
default tracecontext+baggage, setting a noop CompositePropagator when no
propagator is configured.

Assisted-by: Claude Sonnet 4.6
Assisted-by: Claude Sonnet 4.6
- _resource.py: refactor _coerce_attribute_value to dispatch table to
  avoid too-many-return-statements; fix short variable names k/v ->
  attr_key/attr_val; fix return type of _sdk_default_attributes to
  dict[str, str] to satisfy pyright
- _propagator.py: rename short variable names e -> exc, p -> propagator
- test_resource.py: move imports to top level; split TestCreateResource
  (25 methods) into three focused classes to satisfy too-many-public-methods
- test_propagator.py: add pylint disable for protected-access

Assisted-by: Claude Sonnet 4.6
- replace _sdk_default_attributes() with _DEFAULT_RESOURCE from resources module
- move _coerce_bool into dispatch tables for both scalar and array bool types,
  fixing a bug where bool_array with string values like "false" would coerce
  incorrectly via plain bool() (non-empty string -> True)
- add test for bool_array with string values to cover the bug

Assisted-by: Claude Sonnet 4.6
…erge

- collapse _SCALAR_COERCIONS and _ARRAY_COERCIONS into a single _COERCIONS
  dict using an _array() factory, reducing _coerce_attribute_value to two lines
- process attributes_list before attributes so explicit attributes naturally
  overwrite list entries without needing an explicit guard

Assisted-by: Claude Sonnet 4.6
Assisted-by: Claude Sonnet 4.6
Adds _run_detectors() stub and _filter_attributes() to create_resource(),
providing the shared scaffolding for detector PRs to build on. Detectors
are opt-in: nothing runs unless explicitly listed under
detection_development.detectors in the config. The include/exclude
attribute filter mirrors other SDK behaviour.

Assisted-by: Claude Sonnet 4.6
Merges service.name=unknown_service into base before running detectors,
so detectors (e.g. service) can override it. Previously it was added to
config_attrs and merged last, which would have silently overridden any
detector-provided service.name.

Assisted-by: Claude Sonnet 4.6
@MikeGoldsmith MikeGoldsmith force-pushed the mike/config-resource-detector-service branch from b62c43c to a2b7031 Compare March 20, 2026 14:26
MikeGoldsmith added a commit to MikeGoldsmith/opentelemetry-python that referenced this pull request Mar 20, 2026
Adds service detector support to _run_detectors(): sets a random UUID
for service.instance.id and reads OTEL_SERVICE_NAME for service.name
if set. Explicit config attributes still take priority (merged last).

Assisted-by: Claude Sonnet 4.6
@MikeGoldsmith MikeGoldsmith force-pushed the mike/config-resource-detector-service branch from 6fd726b to 2306b93 Compare March 20, 2026 19:46
@MikeGoldsmith MikeGoldsmith marked this pull request as ready for review March 29, 2026 16:33
@MikeGoldsmith MikeGoldsmith requested a review from a team as a code owner March 29, 2026 16:33
Assisted-by: Claude Sonnet 4.6
"""
if detector_config.service is not None:
attrs: dict[str, object] = {
SERVICE_INSTANCE_ID: str(uuid.uuid4()),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Sets service.instance.id to a random UUID on every process start

I can't remember if this is in the spec already. Feel free to resolve if it is or doesn't need more discussion

Copy link
Copy Markdown
Member Author

@MikeGoldsmith MikeGoldsmith Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is in the spec. The semantic conventions for service.instance.id specify it should be a unique identifier for each instance, with a UUID being the recommended value. The opentelemetry-configuration schema also describes the service detector as populating service.instance.id.

attrs: dict[str, object] = {
SERVICE_INSTANCE_ID: str(uuid.uuid4()),
}
service_name = os.environ.get(OTEL_SERVICE_NAME)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this work along with the OTELResourceDetector?

service_name = environ.get(OTEL_SERVICE_NAME)

Copy link
Copy Markdown
Member Author

@MikeGoldsmith MikeGoldsmith Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create_resource intentionally does not invoke OTELResourceDetector and does not read OTEL_RESOURCE_ATTRIBUTES — Declarative config's WYSIWYG semantics mean env vars don't bleed in unless explicitly configured. The one env var the service detector does read is OTEL_SERVICE_NAME, which is intentional per the opentelemetry-configuration schema ("populates service.name based on the OTEL_SERVICE_NAME environment variable"). Java's implementation does the same. JS diverges by only setting service.instance.id and leaving OTEL_SERVICE_NAME to a separate env detector, which may be a bug there (I'm also helping out there so can fix it there too).

Assisted-by: Claude Sonnet 4.6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Approved PRs

Development

Successfully merging this pull request may close these issues.

3 participants